﻿using System;
using OhioState.AssetManaged;

namespace OhioState.Graphics
{
    /// <summary>
    /// Encapsulates a <typeparamref name="IDrawable"/> within an <typeparamref name="IAssetManaged"/>
    /// instance. This allows subscribers to be notified of changes to the drawable, and the drawable
    /// to be replaced without having to unsubscribe and resubscribe to the new drawable.
    /// </summary>
    public class DrawableNodeProxy : SharedAsset, IDrawable
    {
        /// <summary>
        /// Constructor for DrawableNodeProxy
        /// </summary>
        /// <param name="name">Name of the asset as a string.</param>
        /// <param name="drawable">The <typeparamref name="IDrawable"/> object</param>
        public DrawableNodeProxy(String name, IDrawable drawable)
            : base(name)
        {
            if (drawable == null)
                throw new ArgumentNullException("The IDrawable can not be null");

            SetDrawable(drawable);
        }

        /// <summary>
        /// Get and set the real Drawable
        /// </summary>
        public IDrawable Drawable
        {
            get { return realDrawable; }
            set
            {
                SetDrawable(value);
            }
        }

        #region IDrawable Members
        /// <summary>
        /// Implementation of IDrawable BoundingVolume 
        /// </summary>
        public IBoundingVolume BoundingVolume
        {
            get
            {
                return realDrawable.BoundingVolume;
            }
        }
        /// <summary>
        /// Get and set the Material for the underlying drawable.
        /// </summary>
        public IMaterial Material
        {
            get
            {
                return realDrawable.Material;
            }
            set
            {
                realDrawable.Material = value;
                FireUpdateChangedEvent(this);
            }
        }

        /// <summary>
        /// IDrawable implementation of the Render method
        /// </summary>
        /// <param name="panel">A <typeparamref name="IRenderPanel"/> instance to be
        /// used as the context for the rendering.</param>
        /// <remarks>This is a proxy object, and this method will throw an exception if
        /// called on a proxy object.</remarks>
        void IDrawable.Render(IRenderPanel panel)
        {
            throw new NotImplementedException("Proxy objects do not have behaviors");
        }
        #endregion

        private void SetDrawable(IDrawable drawable)
        {
            IAssetManaged asset = realDrawable as IAssetManaged;
            if (asset != null)
            {
                asset.RemoveChangedEventHandler(FireUpdateChangedEvent);
                asset.RemoveChangingEventHandler(FireUpdateChangingEvent);
            }
            realDrawable = drawable;
            asset = realDrawable as IAssetManaged;
            if (asset != null)
            {
                asset.AddChangedEventHandler(FireUpdateChangedEvent);
                asset.AddChangingEventHandler(FireUpdateChangingEvent);
            }
            FireUpdateChangedEvent(this);
        }

        private IDrawable realDrawable;
    }
}
